package com.xunmall.executors.client;

import com.xunmall.executors.framework.EnhancedThreadPoolExecutor;
import com.xunmall.executors.framework.ExecutorGroup;
import com.xunmall.executors.framework.ExecutorGroupMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author wangyj03@zenmen.com
 * @description 默认的监控实现类，定期上报 {@see EnhancedThreadPoolExecutor.ExecutorStats 数据到 monitor 平台}
 * 	            XXX 使用方可以自定义监控实现
 * @date 2020/9/28 18:55
 */
public class DefaultExecutorGroupMonitor implements ExecutorGroupMonitor {
    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * "monitorCodes":["工作线程负荷", "任务的完成率", "队列中的任务数", "reject数量"]
     * 目前只支持以上四个维度的监控
     */
    private ExecutorGroup executorGroup;

    public void setExecutorGroup(ExecutorGroup executorGroup) {
        this.executorGroup = executorGroup;
    }

    /**
     * 启动定时上报监控数据
     */
    public void start() {
        Assert.notNull(executorGroup);
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    monitor();
                } catch (Exception e) {
                    logger.error("monitor executor error", e);
                }
            }
        }, 10, 5, TimeUnit.SECONDS);
    }

    @Override
    public void monitor() {
        List<EnhancedThreadPoolExecutor> executors = executorGroup.all();
        for (EnhancedThreadPoolExecutor executor : executors) {
            EnhancedThreadPoolExecutor.ExecutorStats stats = executor.stats();
            logger.info(String.format(
                    "============ Monitor Executor[%s], activeThreadLoad[%s], taskCompletionRate[%s], queueSize[%s], rejectedCount[%s]",
                    executor.getName(), stats.getActiveThreadLoad(), stats.getTaskCompletionRate(),
                    stats.getQueueSize(), stats.getRejectedCount()));
        }
    }
}
